package com.atguigu.tingshu.album.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.Assert;
import com.atguigu.tingshu.album.mapper.AlbumInfoMapper;
import com.atguigu.tingshu.album.mapper.AlbumStatMapper;
import com.atguigu.tingshu.album.mapper.TrackInfoMapper;
import com.atguigu.tingshu.album.mapper.TrackStatMapper;
import com.atguigu.tingshu.album.service.AuditService;
import com.atguigu.tingshu.album.service.TrackInfoService;
import com.atguigu.tingshu.album.service.VodService;
import com.atguigu.tingshu.common.cache.GuiGuCache;
import com.atguigu.tingshu.common.constant.SystemConstant;
import com.atguigu.tingshu.model.album.AlbumInfo;
import com.atguigu.tingshu.model.album.AlbumStat;
import com.atguigu.tingshu.model.album.TrackInfo;
import com.atguigu.tingshu.model.album.TrackStat;
import com.atguigu.tingshu.query.album.TrackInfoQuery;
import com.atguigu.tingshu.user.client.UserFeignClient;
import com.atguigu.tingshu.vo.album.*;
import com.atguigu.tingshu.vo.user.UserInfoVo;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

import static com.atguigu.tingshu.common.constant.SystemConstant.ALBUM_PAY_TYPE_REQUIRE;
import static com.atguigu.tingshu.common.constant.SystemConstant.ALBUM_PAY_TYPE_VIPFREE;

@Slf4j
@Service
@SuppressWarnings({"all"})
public class TrackInfoServiceImpl extends ServiceImpl<TrackInfoMapper, TrackInfo> implements TrackInfoService {

    @Autowired
    private TrackInfoMapper trackInfoMapper;

    @Autowired
    private AlbumInfoMapper albumInfoMapper;

    @Autowired
    private VodService vodService;

    @Autowired
    private TrackStatMapper trackStatMapper;

    @Autowired
    private AuditService auditService;

    @Autowired
    private UserFeignClient userFeignClient;

    @Autowired
    private AlbumStatMapper albumStatMapper;

    /**
     * 保存声音
     *
     * @param trackInfoVo
     * @param userId
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void saveTrackInfo(TrackInfoVo trackInfoVo, Long userId) {
        //1. 根据专辑id查询专辑信息 用于更新专辑声音数量
        AlbumInfo albumInfo = albumInfoMapper.selectById(trackInfoVo.getAlbumId());
        //2. 保存声音信息
        //2.1 将VO转为PO对象
        TrackInfo trackInfo = BeanUtil.copyProperties(trackInfoVo, TrackInfo.class);
        //2.2 属性赋值
        //2.2.1 基本属性：用户ID，审核状态，封面图片，来源
        trackInfo.setUserId(userId);
        trackInfo.setStatus(SystemConstant.TRACK_STATUS_NO_PASS);
        trackInfo.setSource(SystemConstant.TRACK_SOURCE_USER);
        if (StringUtils.isBlank(trackInfo.getCoverUrl())) {
            //如果用户没有选择封面图片 则用户所属专辑的封面图片
            trackInfo.setCoverUrl(albumInfo.getCoverUrl());
        }

        //2.2.2 计算声音序号 现有专辑包含声音数量+1
        trackInfo.setOrderNum(albumInfo.getIncludeTrackCount() + 1);

        //2.2.3 查询点播平台获取音频详情：得到时长、大小、类型
        TrackMediaInfoVo mediaInfoVo = vodService.getMediaInfo(trackInfo.getMediaFileId());
        if (mediaInfoVo != null) {
            trackInfo.setMediaDuration(BigDecimal.valueOf(mediaInfoVo.getDuration()));
            trackInfo.setMediaSize(mediaInfoVo.getSize());
            trackInfo.setMediaType(mediaInfoVo.getType());
        }

        albumInfoMapper.updateById(albumInfo);

        //2.2.5 保存声音记录
        trackInfoMapper.insert(trackInfo);

        //2.2.4 TODO 调用内容审核接口，发起内容审核，更新审核任务ID
        String text = trackInfo.getTrackTitle() + trackInfo.getTrackIntro();
        String suggestion = auditService.auditText(text);
        if ("pass".equals(suggestion)) {
            trackInfo.setStatus(SystemConstant.TRACK_STATUS_PASS);
            //TODO 文本审核通过后，还需要进一步审核音频内容
            String reviewTaskId = auditService.startReviewTask(trackInfo.getMediaFileId());
            trackInfo.setStatus(SystemConstant.TRACK_STATUS_REVIEWING);
            trackInfo.setReviewTaskId(reviewTaskId);
        } else if ("block".equals(suggestion)) {
            trackInfo.setStatus(SystemConstant.TRACK_STATUS_NO_PASS);
        } else if ("review".equals(suggestion)) {
            trackInfo.setStatus(SystemConstant.TRACK_STATUS_ARTIFICIAL);
        }
        trackInfoMapper.updateById(trackInfo);

        //3. 更新专辑包含声音数量
        albumInfo.setIncludeTrackCount(albumInfo.getIncludeTrackCount() + 1);
        albumInfoMapper.updateById(albumInfo);

        //3.新增声音统计信息
        this.saveTrackStat(trackInfo.getId(), SystemConstant.TRACK_STAT_PLAY, 0);
        this.saveTrackStat(trackInfo.getId(), SystemConstant.TRACK_STAT_COLLECT, 0);
        this.saveTrackStat(trackInfo.getId(), SystemConstant.TRACK_STAT_PRAISE, 0);
        this.saveTrackStat(trackInfo.getId(), SystemConstant.TRACK_STAT_COMMENT, 0);

    }

    /**
     * 保存声音统计信息
     *
     * @param trackId  声音ID
     * @param statType 统计类型：播放、点赞、收藏、评论
     * @param statNum  统计数值
     */
    @Override
    public void saveTrackStat(Long trackId, String statType, int statNum) {
        TrackStat trackStat = new TrackStat();
        trackStat.setTrackId(trackId);
        trackStat.setStatType(statType);
        trackStat.setStatNum(statNum);
        trackStatMapper.insert(trackStat);
    }

    /**
     * 分页条件查询当前用户声音列表
     *
     * @param pageInfo       分页对象
     * @param trackInfoQuery 查询条件
     * @return 分页对象
     */
    @Override
    public Page<TrackListVo> findUserTrackPage(Page<TrackListVo> pageInfo, TrackInfoQuery trackInfoQuery) {
        return trackInfoMapper.findUserTrackPage(pageInfo, trackInfoQuery);
    }

    /**
     * 修改声音
     *
     * @param id
     * @param trackInfoVo
     * @return
     */
    @Override
    public void updateTrackInfo(Long id, TrackInfoVo trackInfoVo) {
        //1. 根据id查询声音信息 得到"原有的"音频唯一标识
        TrackInfo trackInfo = trackInfoMapper.selectById(id);
        String oldMediaFileId = trackInfo.getMediaFileId();

        //对文本进行审核
        String text = trackInfoVo.getTrackTitle() + trackInfoVo.getTrackIntro();
        String suggestion = auditService.auditText(text);
        if ("pass".equals(suggestion)) {
            trackInfo.setStatus(SystemConstant.TRACK_STATUS_PASS);
        } else if ("block".equals(suggestion)) {
            trackInfo.setStatus(SystemConstant.TRACK_STATUS_NO_PASS);
        } else if ("review".equals(suggestion)) {
            trackInfo.setStatus(SystemConstant.TRACK_STATUS_ARTIFICIAL);
        }

        //2. 判断音频文件是否发生更新，如果更新
        if (!trackInfoVo.getMediaFileId().equals(oldMediaFileId)) {
            // 2.1 调用点播平台获取最新音频详情信息
            TrackMediaInfoVo mediaInfo = vodService.getMediaInfo(trackInfoVo.getMediaFileId());
            if (mediaInfo != null) {
                trackInfo.setMediaFileId(trackInfoVo.getMediaFileId());
                trackInfo.setMediaUrl(trackInfoVo.getMediaUrl());
                trackInfo.setMediaDuration(BigDecimal.valueOf(mediaInfo.getDuration()));
                trackInfo.setMediaType(mediaInfo.getType());
                trackInfo.setMediaSize(mediaInfo.getSize());
                // 2.2 TODO 再次对变更后音频文件进行内容审核
                String reviewTaskId = auditService.startReviewTask(trackInfo.getMediaFileId());
                trackInfo.setStatus(SystemConstant.TRACK_STATUS_REVIEWING);
                trackInfo.setReviewTaskId(reviewTaskId);

                // 2.3原有音频从点播平台删除
                vodService.deleteMedia(oldMediaFileId);
            }
        }
        trackInfo.setTrackTitle(trackInfoVo.getTrackTitle());
        trackInfo.setTrackIntro(trackInfoVo.getTrackIntro());
        trackInfo.setCoverUrl(trackInfoVo.getCoverUrl());


        //3. 更新声音记录
        trackInfoMapper.updateById(trackInfo);
    }

    /**
     * 删除声音
     *
     * @param id
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void removeTrackInfo(Long id) {
        //1.根据ID查询要被删除声音记录 得到专辑ID跟序号
        TrackInfo trackInfo = trackInfoMapper.selectById(id);
        Long albumId = trackInfo.getAlbumId();
        Integer orderNum = trackInfo.getOrderNum();

        //2.更新序号确保声音表中序号连续
        trackInfoMapper.update(
                null,
                new LambdaUpdateWrapper<TrackInfo>()
                        .eq(TrackInfo::getAlbumId, albumId)
                        .gt(TrackInfo::getOrderNum, orderNum)
                        .setSql("order_num = order_num - 1")
        );

        //3.删除声音
        trackInfoMapper.deleteById(id);

        //4.删除统计信息
        trackStatMapper.delete(
                new LambdaQueryWrapper<TrackStat>()
                        .eq(TrackStat::getTrackId, id)
        );

        //5.更新专辑包含声音数量
        albumInfoMapper.update(null,
                new LambdaUpdateWrapper<AlbumInfo>().eq(AlbumInfo::getId, albumId)
                        .setSql("include_track_count = include_track_count - 1")
        );

        //6.删除点播平台音频文件
        vodService.deleteMedia(trackInfo.getMediaFileId());
    }

    /**
     * 分页查询专辑下包含声音列表（动态展示付费标识）
     *
     * @param pageInfo 分页对象
     * @param userId   用户ID
     * @param albumId  专辑ID
     * @return 分页对象
     */
    @Override
    public Page<AlbumTrackListVo> findAlbumTrackPage(Page<AlbumTrackListVo> pageInfo, Long userId, Long albumId) {
        //1.分页查询专辑下声音列表 默认：isShowPaidMark = false;
        pageInfo = trackInfoMapper.findAlbumTrackPage(pageInfo, albumId);
        //TODO 根据用户登录状态、身份、专辑付费类型、是否购买综合判断付费标识

        //2.根据专辑ID查询专辑信息，得到专辑付费类型以及免费试听集数
        AlbumInfo albumInfo = albumInfoMapper.selectById(albumId);

        //付费类型: 0101-免费、0102-vip免费、0103-付费
        String payType = albumInfo.getPayType();
        Integer tracksForFree = albumInfo.getTracksForFree();

        //3.处理未登录情况
        if (userId == null) {
            if (ALBUM_PAY_TYPE_VIPFREE.equals(payType) || ALBUM_PAY_TYPE_REQUIRE.equals(payType)) {
                //将试听以外其他声音付费标识改为：true
                pageInfo.getRecords()
                        .stream()
                        .filter(track -> track.getOrderNum() > tracksForFree)
                        .forEach(track -> track.setIsShowPaidMark(true));
            }
        } else {
            //4.处理已登录情况
            //4.1 远程调用用户服务获取用户身份，是否为VIP
            Boolean isVIP = false;
            UserInfoVo userInfoVo = userFeignClient.getUserInfoVo(userId).getData();
            Assert.notNull(userInfoVo, "用户{}不存在", userId);
            if (userInfoVo.getIsVip().intValue() == 1
                    && userInfoVo.getVipExpireTime().after(new Date())) {
                isVIP = true;
            }

            Boolean isNeedCheckPayState = false;
            //4.2 如果普通用户查看付费类型是：VIP免费专辑，则需要进一步判断声音购买情况
            if (!isVIP && ALBUM_PAY_TYPE_VIPFREE.equals(payType)) {
                isNeedCheckPayState = true;
            }

            //4.3 如果付费类型是：付费。无论什么用户，都需要进一步判断声音购买情况
            if (ALBUM_PAY_TYPE_REQUIRE.equals(payType)) {
                isNeedCheckPayState = true;
            }
            //4.4 如果需要判断声音购买情况，远程调用用户服务
            if (isNeedCheckPayState) {
                //4.4.1 获取当前页中去掉试听部分声音ID列表
                List<Long> needCheckPayStateTrackIdList = pageInfo.getRecords()
                        .stream()
                        .filter(track -> track.getOrderNum() > tracksForFree)
                        .map(AlbumTrackListVo::getTrackId)
                        .collect(Collectors.toList());
                //4.4.2 远程调用用户服务获取每个声音的购买情况
                Map<Long, Integer> payStatusMap = userFeignClient.userIsPaidTrack(albumId, needCheckPayStateTrackIdList).getData();

                //4.5 根据响应声音购买情况，(去除掉试听部分声音ID)将未购买声音付费标识设置为：true
                pageInfo.getRecords()
                        .stream()
                        .filter(track -> track.getOrderNum() > tracksForFree)
                        .forEach(track -> track.setIsShowPaidMark(payStatusMap.get(track.getTrackId()) == 0));
            }
        }
        return pageInfo;
    }

    /**
     * 获取声音统计信息
     *
     * @param trackId
     * @return
     */
    @Override
    @GuiGuCache(prefix = "album:trackInfo:stat:")
    public TrackStatVo getTrackStatVo(Long trackId) {
        return trackInfoMapper.getTrackStatVo(trackId);
    }

    /**
     * 更新声音/专辑统计信息
     *
     * @param mqVo
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateStat(TrackStatMqVo mqVo) {
        //1.先更新声音统计数值
        trackStatMapper.update(
                null,
                new LambdaUpdateWrapper<TrackStat>()
                        .eq(TrackStat::getTrackId, mqVo.getTrackId())
                        .eq(TrackStat::getStatType, mqVo.getStatType())
                        .setSql("stat_num = stat_num +" + mqVo.getCount())
        );

        //2.如果是声音播放、评论。还需要更新声音所属专辑统计数值
        if (SystemConstant.TRACK_STAT_PLAY.equals(mqVo.getStatType())) {
            albumStatMapper.update(
                    null,
                    new LambdaUpdateWrapper<AlbumStat>()
                            .eq(AlbumStat::getAlbumId, mqVo.getAlbumId())
                            .eq(AlbumStat::getStatType, SystemConstant.ALBUM_STAT_PLAY)
                            .setSql("stat_num = stat_num +" + mqVo.getCount())
            );
        }

        if (SystemConstant.TRACK_STAT_COMMENT.equals(mqVo.getStatType())) {
            albumStatMapper.update(
                    null,
                    new LambdaUpdateWrapper<AlbumStat>()
                            .eq(AlbumStat::getAlbumId, mqVo.getAlbumId())
                            .eq(AlbumStat::getStatType, SystemConstant.ALBUM_STAT_COMMENT)
                            .setSql("stat_num = stat_num +" + mqVo.getCount())
            );
        }
    }

    /**
     * 基于用户选择声音作为起始标准获取未购买声音数量，得到分集购买列表
     *
     * @param trackId
     * @return [{name:"本集",price:0.1,trackCount:1},{name:"后10集",price:1,trackCount:10},...,{name:"全集",price:4.3,trackCount:43},]
     */
    @Override
    public List<Map<String, Object>> findUserTrackPaidList(Long userId, Long trackId) {
        //1.根据声音ID查询到“起始”选择购买声音记录,获取专辑ID跟序号
        TrackInfo trackInfo = trackInfoMapper.selectById(trackId);
        Long albumId = trackInfo.getAlbumId();
        Integer orderNum = trackInfo.getOrderNum();

        //2.根据"起始"声音序号+专辑ID获取所有“待购买”声音列表（可能包含已购买声音）
        List<TrackInfo> waitBuyTrackList = trackInfoMapper.selectList(
                new LambdaQueryWrapper<TrackInfo>()
                        .eq(TrackInfo::getAlbumId, albumId)
                        .ge(TrackInfo::getOrderNum, orderNum)
                        .select(TrackInfo::getId)
        );

        //3.远程调用用户服务获取已购买声音ID列表
        List<Long> userPaidTrackIdList = userFeignClient.findUserPaidTrackList(albumId).getData();
        if (CollUtil.isNotEmpty(userPaidTrackIdList)) {
            //4.如果存在已购声音ID，则将已购声音ID从待购买声音列表中移除，得到未购买声音数量
            waitBuyTrackList = waitBuyTrackList.stream()
                    .filter(track -> !userPaidTrackIdList.contains(track.getId()))
                    .collect(Collectors.toList());
        }
        //5.基于未购买声音数量，生成分集购买列表
        int size = waitBuyTrackList.size();
        AlbumInfo albumInfo = albumInfoMapper.selectById(albumId);
        BigDecimal price = albumInfo.getPrice();
        //5.1 创建分集购买集合List
        List<Map<String, Object>> list = new ArrayList<>();
        //5.2 构建"本集"分集购买对象
        Map<String, Object> currMap = new HashMap<>();
        currMap.put("name", "本集");
        currMap.put("price", price);
        currMap.put("trackCount", 1);
        list.add(currMap);
        //5.3 构建其他"后*集"分集购买对象   未购买数量：23    43
        for (int i = 10; i <= 50; i += 10) {
            Map<String, Object> map = new HashMap<>();
            if (size >= i) {
                map.put("name", "后" + i + "集");
                map.put("price", price.multiply(new BigDecimal(i)));
                map.put("trackCount", i);
                list.add(map);
            } else {
                map.put("name", "全集(后" + size + "集)");
                map.put("price", price.multiply(new BigDecimal(size)));
                map.put("trackCount", size);
                list.add(map);
                break;
            }
        }
        return list;
    }

    /**
     * 基于选择购买声音ID作为起始获取指定数量未购买声音列表
     *
     * @param trackId
     * @param trackCount
     * @return
     */
    @Override
    public List<TrackInfo> findPaidTrackInfoList(Long userId, Long trackId, Integer trackCount) {
        //1.根据选择声音ID查询声音，得到专辑ID跟序号
        TrackInfo trackInfo = trackInfoMapper.selectById(trackId);
        Integer orderNum = trackInfo.getOrderNum();
        Long albumId = trackInfo.getAlbumId();

        //2.远程调用用户服务获取已购买声音ID列表
        List<Long> userPaidTrackIdList = userFeignClient.findUserPaidTrackList(albumId).getData();


        //2.获取指定数量未购买声音列表
        LambdaQueryWrapper<TrackInfo> queryWrapper = new LambdaQueryWrapper<TrackInfo>()
                .eq(TrackInfo::getAlbumId, albumId)
                .ge(TrackInfo::getOrderNum, orderNum)
                .last("limit " + trackCount)
                .select(TrackInfo::getId,TrackInfo::getTrackTitle, TrackInfo::getCoverUrl, TrackInfo::getAlbumId);
        if (CollUtil.isNotEmpty(userPaidTrackIdList)) {
            queryWrapper.notIn(TrackInfo::getId, userPaidTrackIdList);
        }
        List<TrackInfo> trackInfoList = trackInfoMapper.selectList(queryWrapper);
        return trackInfoList;
    }


}
